#include "unione_lite.h"
#include "DrvUART010.h"
#include "i2c.h"

#define FTIIC010_REG_BASE IIC_FTIIC010_0_PA_BASE


//===========================
// Size Type
//===========================
#define HSIZE_WORD    0x2
#define HSIZE_HWORD   0x1
#define HSIZE_HALFWORD   0x1
#define HSIZE_BYTE    0x0

#define WORD  unsigned int
#define HWORD unsigned short
#define BYTE  unsigned char

#define ALI_EN    0x00002000
#define SAMI_EN   0x00001000
#define STOPI_EN  0x00000800
#define BERRI_EN  0x00000400
#define DRI_EN    0x00000200
#define DTI_EN    0x00000100
#define TB_EN     0x00000080
#define NACK      0x00000040
#define STOP      0x00000020
#define START     0x00000010
#define GC_EN     0x00000008
#define SCL_EN    0x00000004
#define I2C_EN    0x00000002
#define I2C_RST   0x00000001

void sw(WORD addr, WORD data, BYTE type)
{
    switch( type ){
        case HSIZE_BYTE:
            *((BYTE  *) addr) = (BYTE) data;
            break;
        case HSIZE_HWORD:
            *((HWORD *) addr) = (HWORD) data;
            break;
        case HSIZE_WORD:
            *((WORD  *) addr) = (WORD) data;
            break;
        default:
            break;
    }
}

// ---------------------------------------------------------------------------
// func: srdata
// ---------------------------------------------------------------------------
void srdata (WORD addr, WORD *data)
{
  *data=*(volatile WORD *) addr;
}

int I2C_SetSCLout(unsigned int base_addr, unsigned int i_SCLout)
{
	int  i, gsr;
	unsigned int read_SR0;

	i_SCLout = i_SCLout *1000 ;
	if ( i_SCLout == 0 )
	{
		i_SCLout = I2C_Default_FREQ;		// default. clock is 45KHz
	}
	
	if (i_SCLout > I2C_MAX_FREQ) 
	{
		i_SCLout = I2C_MAX_FREQ;			// max. clock is 400KHz
	}

    srdata(base_addr+I2C_TGSR, &read_SR0);

	gsr = (read_SR0 >> 10) & 0x7;

	//fLib_printf("+++gsr = %d\r\n",gsr);
	
	//i = (divRoundUp(APB_CLK, i_SCLout) + gsr - 1 + 1) / 2;

	i = (divRoundUp(APB_CLK, i_SCLout)-gsr-4)>>1;
	//fLib_printf("+++count = %d\r\n",i);
	if (i >= BIT10) 
	{
		fLib_printf("APB_CLK=%d, i_SCLout=%d\n",APB_CLK, i_SCLout);
		fLib_printf("Pclk is too fast to form i2c clock, fail \n");
		return -1;
	}

	sw(base_addr+I2C_CDR, i, HSIZE_WORD);
	return 0;
}


void i2c_init(void)
{
  unsigned int read_SR0;
  sw(FTIIC010_REG_BASE+I2C_CR, I2C_RST, HSIZE_WORD); // reset

  do{
     srdata(FTIIC010_REG_BASE+I2C_CR, &read_SR0);
  }while(read_SR0 & I2C_RST);

  sw(FTIIC010_REG_BASE+I2C_TGSR, (I2C_GSR_Value<<10) | I2C_TSR_Value, HSIZE_WORD);

  srdata(FTIIC010_REG_BASE+I2C_TGSR,&read_SR0);
  //fLib_printf("TGSR is 0x%x\r\n",read_SR0);

  I2C_SetSCLout(FTIIC010_REG_BASE,100);//100k

  //sw(FTIIC010_REG_BASE+I2C_TGSR, 0x801, HSIZE_WORD);
  //sw(FTIIC010_REG_BASE+0x08, 0x00800134, HSIZE_WORD);
}

int i2c_write(unsigned char slave_addr, unsigned char* buf, unsigned int length, int stop_en)
{
  unsigned int read_SR0;
  int i;
  //--------------------------
  sw(FTIIC010_REG_BASE+0x0c, slave_addr << 1, HSIZE_WORD ); 

  sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | START | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);

  srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
  //TODO:: uart_pritnf sometimes may lead to I2C failure
  //fLib_printf("I2C wr1= %x\r\n",read_SR0);

  while((read_SR0 & 0x20) != 0x20) 
  {
    srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
  }
  sw(FTIIC010_REG_BASE+0x04, read_SR0, HSIZE_WORD);

  //--------------------------
  for (i = 0; i < length; i++) 
  {
    sw(FTIIC010_REG_BASE+0x0c, buf[i], HSIZE_WORD);

    if ((i == (length - 1)) && (stop_en))
      sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | STOP | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);
    else
      sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);

    srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
    //TODO:: uart_pritnf sometimes may lead to I2C failure

    while((read_SR0 & 0x20) != 0x20)
    {
      srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
    }
    sw(FTIIC010_REG_BASE+0x04, read_SR0, HSIZE_WORD);
  }
  return 0;
}

int i2c_read(unsigned char slave_addr, unsigned char* buf, unsigned int length)
{
  unsigned int read_SR0, wonder_SR0;
  int i;
  //--------------------------
  sw(FTIIC010_REG_BASE+0x0c, (slave_addr << 1) | 1, HSIZE_WORD ); 

  //sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);
  sw(FTIIC010_REG_BASE+0x00, 0x3f96, HSIZE_WORD);

  srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
  while((read_SR0 & 0x20) != 0x20) 
  {
    srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
  }
  sw(FTIIC010_REG_BASE+0x04, read_SR0, HSIZE_WORD);

  //--------------------------
  for (i = 0; i < length; i++) 
  {
    if (i == (length - 1))
    {
      sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | NACK | STOP | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);
      wonder_SR0 = 0x60;
    }
    else
    {
      sw(FTIIC010_REG_BASE+0x00, ALI_EN | SAMI_EN |  BERRI_EN | DRI_EN | DTI_EN | TB_EN | GC_EN | SCL_EN | I2C_EN, HSIZE_WORD);
      wonder_SR0 = 0x20;
    }
    srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
    while((read_SR0 & wonder_SR0) != wonder_SR0) 
    {
      srdata(FTIIC010_REG_BASE+0x04, &read_SR0);
    }
    sw(FTIIC010_REG_BASE+0x04, read_SR0, HSIZE_WORD);
    srdata(FTIIC010_REG_BASE+0x0c, &read_SR0);
    buf[i] = read_SR0;
  }
  return 0;
}

